// 将其他模块结合起来使用
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef LOGGER_HPP
#define LOGGER_HPP
#include "logLevel.hpp"
#include "logSink.hpp"
#include "formatter.hpp"
#include "logMessage.hpp"
#include "looper.hpp"
#include <atomic>
#include <cstdarg>
#include <cstdio>
#include <thread>
#include <mutex>
#include <unordered_map>
#include <shared_mutex>

namespace blog
{
    class logger
    {
    public:
        using ptr = std::shared_ptr<logger>;

    public:
        logger(std::string logger_name, logLevel::value limit_level, formatter::ptr formatter, std::vector<logSink::ptr> sinks)
            : _logger_name(logger_name),
              _limit_level(limit_level),
              _sinks(sinks),
              _format(formatter)
        {
        }

    public:
        const std::string& name()
        {
            return _logger_name;
        }
        void Debug(std::string filename, size_t line, std::string format, ...)
        {
            if (logLevel::value::DEBUG < _limit_level)
                return;
            va_list args;
            va_start(args, format);
            char *res;
            int ret = vasprintf(&res, format.c_str(), args);
            if (ret < 0)
            {
                std::cout << "获取信息失败" << std::endl;
            }
            va_end(args);
            serializeAndlog(filename, line, logLevel::value::DEBUG, res);
            free(res); // 十分重要,res被vasprintf后会被动态分配一个空间,不会自动释放;
        }
        void Info(std::string filename, size_t line, std::string format, ...)
        {

            if (logLevel::value::INFO < _limit_level)
                return;
            va_list args;
            va_start(args, format);
            char *res;
            int ret = vasprintf(&res, format.c_str(), args);
            if (ret < 0)
            {
                std::cout << "获取信息失败" << std::endl;
            }
            va_end(args);
            serializeAndlog(filename, line, logLevel::value::INFO, res);
            free(res);
        }
        void Warn(std::string filename, size_t line, std::string format, ...)
        {

            if (logLevel::value::WARN < _limit_level)
                return;
            va_list args;
            va_start(args, format);
            char *res;
            int ret = vasprintf(&res, format.c_str(), args);
            if (ret < 0)
            {
                std::cout << "获取信息失败" << std::endl;
            }
            va_end(args);
            serializeAndlog(filename, line, logLevel::value::WARN, res);
            free(res);
        }
        void Err(std::string filename, size_t line, std::string format, ...)
        {

            if (logLevel::value::ERR < _limit_level)
                return;
            va_list args;
            va_start(args, format);
            char *res;
            int ret = vasprintf(&res, format.c_str(), args);
            if (ret < 0)
            {
                std::cout << "获取信息失败" << std::endl;
            }
            va_end(args);
            serializeAndlog(filename, line, logLevel::value::ERR, res);
            free(res);
        }
        void Fatal(std::string filename, size_t line, std::string format, ...)
        {

            if (logLevel::value::FATAL < _limit_level)
                return;
            va_list args;
            va_start(args, format);
            char *res;
            int ret = vasprintf(&res, format.c_str(), args);
            if (ret < 0)
            {
                std::cout << "获取信息失败" << std::endl;
            }
            va_end(args);
            serializeAndlog(filename, line, logLevel::value::FATAL, res);
            free(res);
        }

    protected:
        // 将接收到的信息格式化,并落地
        void serializeAndlog(std::string &filename, size_t line, logLevel::value level, std::string m)
        {
            logMessage msg("test", level, filename, line, m);
            std::stringstream ss;
            _format->format(ss, msg);
            // 日志落地
            log(ss.str().c_str(), ss.str().size());
        }
        virtual void log(const char *data, size_t len) = 0;

    protected:
        std::mutex _mutex;
        std::string _logger_name;
        std::atomic<logLevel::value> _limit_level; // 设成原子的,提升运行效率
        std::vector<logSink::ptr> _sinks;
        formatter::ptr _format;
    };
    //同步日志器
    class syncLogger : public logger
    {
    public:
        syncLogger(std::string logger_name, logLevel::value limit_level, formatter::ptr formatter, std::vector<logSink::ptr> sinks)
            : logger(logger_name, limit_level, formatter, sinks)
        {
        }

    protected:
        // 通过日志落地模块,进行输出
        void log(const char *data, size_t len)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->log(data, len);
            }
        }
    };
    //异步日志器
    class asyncLogger:public logger
    {
    public:
        using ptr=std::shared_ptr<asyncLogger>;
    public:
        asyncLogger(std::string logger_name, logLevel::value limit_level, formatter::ptr formatter, std::vector<logSink::ptr> sinks,looper_type lt)
            : logger(logger_name, limit_level, formatter, sinks),
            _lt(lt),
            _lp(std::make_shared<looper>(std::bind(&asyncLogger::realLog,this,std::placeholders::_1),lt))
            {}
        //将数据写入缓冲区
        void log(const char*data,size_t len)
        {
            _lp->push(data,len);
        }
    private:
        //将缓冲区中的数据落地
        void realLog(buffer& buffer)
        {
            //异步日志器工作只有一个线程 而且消费者和生产者已经是串行化运行了 所以不用上锁
             if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->log(buffer.begin(), buffer.readAble_len());
            }
        }
    private:
        looper::ptr _lp;
        looper_type _lt;
    };
    // 日志建造者基类
    enum class log_type
    {
        SYNC_LOG,
        ASYNC_LOG
    };
    class logger_bulider
    {
    public:
        using ptr = std::shared_ptr<logger_bulider>;
        logger_bulider(looper_type lt=looper_type::SAFE_TYPE):_limit_level(logLevel::value::DEBUG){}
    public:
        void bulid_loggerName(std::string logger_name) { _logger_name = logger_name; }
        void bulid_limitLevel(logLevel::value limit_level) { _limit_level = limit_level; }
        void bulid_logType(log_type log_type) { _log_type = log_type; }
        void bulid_format(std::string &pattern)
        {
            _format = std::make_shared<formatter>(pattern);
        }
        template <typename SinkType, typename... Args>
        void bulid_logSink(Args &&...args)
        {
            _sinks.push_back(std::make_shared<SinkType>(std::forward<Args>(args)...));
        }

    public:
        virtual logger::ptr bulid() = 0;

    protected:
        std::string _logger_name;
        std::atomic<logLevel::value> _limit_level;
        std::vector<logSink::ptr> _sinks;
        log_type _log_type;
        formatter::ptr _format;
        looper_type _lt;
    };
    // 派生局部日志器建造者和全局日志器建造者
    class local_logger_bulider : public logger_bulider
    {
    
    public:
        logger::ptr bulid() override
        {
            if (_logger_name.empty())//如果没有日志器名字,在日志器管理模块中就无法进行管理
            {
                std::cerr << "未设置日志器名字" << std::endl;
                return NULL;
            }
            //如果没有设置就进行默认参数设置
            if (_format.get() == nullptr)
            {
                _format = std::make_shared<formatter>();
            }
            if (_sinks.empty())
            {
                bulid_logSink<stdoutSink>();
            }
            if (_log_type == log_type::SYNC_LOG)
            {
                return std::make_shared<syncLogger>(_logger_name, _limit_level, _format, _sinks);
            }
            else
            {
                return std::make_shared<asyncLogger>(_logger_name, _limit_level, _format, _sinks,_lt);
                
            }
        }
    };
     
    class logger_manager
    {
    public:
        static logger_manager& get_instance()
        {
            static logger_manager lm;//c++11 实现了局部静态变量的创建线程安全 所以不需要上锁
            return lm;        
        }
        void addLogger(logger::ptr logger)
        {
            if(hasLogger(logger))   return; //放到锁里面 就会调用一把锁两次 导致死锁
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(),logger));
        }
        bool hasLogger(logger::ptr logger)
        {
            std::unique_lock<std::mutex> lock(_mutex);//防止出现数据竞争 迭代器失效等问题 所以上锁
            auto it=_loggers.find(logger->name());
            if(it==_loggers.end())return false;
            return true;
        }
        logger::ptr getLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it=_loggers.find(name);
            if(it==_loggers.end())  return logger::ptr();
            return it->second;
        }
        logger::ptr rootLogger()
        {
            return _root;
        }
    private:
        logger_manager()
        {
            logger_bulider::ptr lb=std::make_shared<local_logger_bulider>();
            lb->bulid_loggerName("root");
            _root=lb->bulid();
            _loggers.insert(std::make_pair("root",_root));
        }
    private:
        logger::ptr _root;//默认日志器
        std::unordered_map<std::string,logger::ptr> _loggers;
        std::mutex _mutex;
    };
   
    class global_logger_bulider : public logger_bulider
    {
    public:
        logger::ptr bulid() override
        {
            if (_logger_name.empty())//如果没有日志器名字,在日志器管理模块中就无法进行管理
            {
                std::cerr << "未设置日志器名字" << std::endl;
                return NULL;
            }
            //如果没有设置就进行默认参数设置
            if (_format.get() == nullptr)
            {
                _format = std::make_shared<formatter>();
            }
            if (_sinks.empty())
            {
                bulid_logSink<stdoutSink>();
            }
            logger::ptr logger;
            if (_log_type == log_type::SYNC_LOG)
            {
                logger= std::make_shared<syncLogger>(_logger_name, _limit_level, _format, _sinks);
            }
            else
            {
                logger= std::make_shared<asyncLogger>(_logger_name, _limit_level, _format, _sinks,_lt);
                
            }
            //添加到日志管理器 管理
            logger_manager::get_instance().addLogger(logger);
            return logger;
        }
    };
}
#endif